package net.tngou.tpage.jdbc;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Hashtable;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 数据库连接管理
 * 
 * @author w.s
 *
 */
public class DBManagerExt {

	private final static Logger log = LoggerFactory.getLogger(DBManagerExt.class);
	private final static ThreadLocal<Hashtable<String, Connection>> connectionsTable = new ThreadLocal<Hashtable<String, Connection>>();
	private static Hashtable<String,DataSource> dataSourceTable = new Hashtable<String,DataSource>();
	private static boolean show_sql = false;

//	/**
//	 * 初始化连接池
//	 * 待继续改造
//	 * @param dbProperties
//	 * @param show_sql
//	 */
//	private final static void initDataSource(String devNo,String ip,String port,String dbName,String username,String password) {
//		try {
//			Map<String, String> cp_props = new HashMap<String, String>();// 使用cp_props做临时的配置文件的存储
//			
//			cp_props.put("driverClassName", "com.mysql.jdbc.Driver");
//			String url = "jdbc:mysql://"+ip+":"+port+"/"+dbName+"?characterEncoding=utf8";
//			cp_props.put("url", url);
//			cp_props.put("username", username);
//			cp_props.put("password", password);
//			
//			// 从配置文件中对取使用的链接池
//			// Class.forName(cp_props.getProperty("driverClassName"));//加载驱动，由于在web发布时不能自动加载
//			if(dataSourceTable==null){
//				dataSourceTable = new Hashtable<String,DataSource>();
//			}
//			DataSource dataSource = (DataSource) Class.forName("com.alibaba.druid.pool.DruidDataSource").newInstance();
//			dataSourceTable.put(devNo, dataSource);
//			
//			log.info("使用  DataSource : " + dataSource.getClass().getName());
//			BeanUtils.populate(dataSource, cp_props);// 把配置文件的值封装到dataSource
//
//			Connection conn = getConnection(devNo);// 测试链接
//			DatabaseMetaData mdm = conn.getMetaData();
//			log.info("Connected to " + mdm.getDatabaseProductName() + " " + mdm.getDatabaseProductVersion());
//			closeConnection(devNo);// 关闭链接
//
//		} catch (Exception e) {
//			log.error("数据库链接失败！\n");
//			e.printStackTrace();
//		}
//
//	}

	/**
	 * 暂时不做 数据 分布在多台机器的 数据源，所以，目前的数据源 使用主服务器的数据源
	 * @param devNo
	 */
	private static final void initDataSource(String devNo){
		try {
			if(dataSourceTable.get(devNo)==null){
				DataSource dataSource = DBManager.getDataSource();
				dataSourceTable.put(devNo, dataSource);
				log.info("初始化DS:"+devNo);
			}		
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 关闭链接
	 */
	public final static void closeConnection(String devNo) {
		if(devNo==null){
			log.error("devNo 不可为 null!");
			return;
		}
		Connection conn = connectionsTable.get().get(devNo);
		try {
			if (conn != null && !conn.isClosed()) {
				conn.setAutoCommit(true);
				conn.close();
			}
		} catch (SQLException e) {
			log.error("不能关闭链接!!! ", e);
		}
		connectionsTable.set(null);
	}

	/**
	 * 断开连接池
	 */

	public final static void closeDataSource() {
		try {
			dataSourceTable.getClass().getMethod("close").invoke(dataSourceTable);
		} catch (NoSuchMethodException e) {
		} catch (Exception e) {
			log.error("Unabled to destroy DataSource!!! ", e);

		}

	}

	/**
	 * 取得链接
	 * 
	 * @return
	 * @throws SQLException
	 */
	public final static Connection getConnection(String devNo) throws SQLException {
		if(devNo!=null){
			initDataSource(devNo);
		}else{
			log.error("devNo 不可为null!");
			return null;
		}
		if(connectionsTable.get()==null){
			connectionsTable.set(new Hashtable<String,Connection>());
		}
		Connection conn = connectionsTable.get().get(devNo);
		if (conn == null || conn.isClosed()) {
			conn = dataSourceTable.get(devNo).getConnection();
			connectionsTable.get().put(devNo, conn);
		}
		return (show_sql && !Proxy.isProxyClass(conn.getClass())) ? new _DebugConnection(conn).getConnection() : conn;

	}

	/**
	 * 用于跟踪执行的SQL语句
	 * 
	 * @author 陈磊
	 *
	 */
	static class _DebugConnection implements InvocationHandler {

		private final static Logger log = LoggerFactory.getLogger(_DebugConnection.class);
		private Connection conn = null;

		public _DebugConnection(Connection conn) {

			this.conn = conn;

		}

		public Connection getConnection() {
			return (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(),
					conn.getClass().getInterfaces(), this);
		}

		@Override
		public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
			try {
				String method = m.getName();
				if ("prepareStatement".equals(method) || "createStatement".equals(method)) {
					if (args != null && args.length > 0) {
						log.info("[SQL] >>> " + args[0]);
					}
				}
				return m.invoke(conn, args);
			} catch (InvocationTargetException e) {
				throw e.getTargetException();
			}
		}

	}

}
